/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef avro_napi_H
#define avro_napi_H
#include "../utils/napi/napi_utils.h"
#include "../utils/ohoslog/ohos_log.h"
#include "avro.h"
#include "avro/basics.h"
#include <napi/native_api.h>
#include <string>
#include <vector>

#include "avro_compareBuffers.h"

#define OHOS_AVRO_ERR_NO INT_MIN

#define RETURN_NULL_VALUE(env)                                                                                         \
    do {                                                                                                               \
        napi_value null_val;                                                                                           \
        /* get null */                                                                                                 \
        if (napi_get_null((env), &null_val) == napi_ok) {                                                              \
            return null_val;                                                                                           \
        }                                                                                                              \
    } while (0)

struct AvroAsyncData {
    napi_async_work work;
    napi_ref callback;
    std::string filePath;
    avro_file_reader_t reader;
    avro_file_writer_t writer;
    avro_schema_t schema;
    std::vector<avro_value_t> result;
    std::string errorMsg;
    std::vector<avro_value_t> write_values;
    bool hasError;
    bool shouldAbort;
};

//// 模拟 JavaScript Array.subarray，返回原vector[start, end)的副本
//template <typename T>
//std::vector<T> subarray(const std::vector<T>& vec, size_t start, size_t end) {
//    // 处理边界：start 不小于 0，end 不大于原vector长度
//    start = std::max(start, (size_t)0);
//    end = std::min(end, vec.size());
//    if (start >= end) {
//        return {}; // 空范围返回空vector
//    }
//    // 通过迭代器范围构造新vector（拷贝元素）
//    return std::vector<T>(vec.begin() + start, vec.begin() + end);
//}

class OhosAvroC {

public:
    static napi_value Construct(napi_env env, napi_callback_info info);
    ~OhosAvroC();
    static std::string GetStringFromNapiValue(napi_env env, napi_value value);
    static napi_value Parse(napi_env env, napi_callback_info info);
    static napi_value GetSchemaTypeName(napi_env env, napi_callback_info info);
    static napi_value GetArrayItemType(napi_env env, napi_callback_info info);

    static napi_value ToBuffer(napi_env env, napi_callback_info info);
    static void ToBuffer_int32(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_int64(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_string(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_float(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_double(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_boolean(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_null(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_enum(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value);
    static void ToBuffer_map(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value);
    static void ToBuffer_array(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value);
    static void ToBuffer_fixed(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value);
    static void ToBuffer_record(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value);
    static void ToBuffer_bytes(napi_env env, napi_value args, avro_value_t *user_value);
    static void ToBuffer_union(napi_env env, avro_schema_t schema, napi_value args, avro_value_t *user_value);
    static void ToBuffer_recursion(avro_type_t type, napi_env env, avro_schema_t schema, napi_value args,
                                   avro_value_t *user_value);
    static bool DataAgainstSchema(napi_env env, napi_value data, avro_schema_t schema, std::string &type_name,
                                  avro_type_t &avro_type, avro_schema_t all_schema);

    static napi_value GetMapValueType(napi_env env, napi_callback_info info);
    static napi_value GetFixedSize(napi_env env, napi_callback_info info);
    static napi_value GetSchema(napi_env env, napi_callback_info info);
    static std::vector<std::string> ExtractAliases(const std::string& avroStr);
    static napi_value GetAliases(napi_env env, napi_callback_info info);

    static napi_value FromBuffer(napi_env env, napi_callback_info info);
    static napi_value FromBuffer_string(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_int32(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_int64(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_bytes(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_float(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_double(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_boolean(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_null(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_record(napi_env env, avro_schema_t schema, avro_value_t &value);
    static napi_value FromBuffer_enum(napi_env env, avro_schema_t schema, avro_value_t &value);
    static napi_value FromBuffer_fixed(napi_env env, avro_value_t &value);
    static napi_value FromBuffer_map(napi_env env, avro_schema_t schema, avro_value_t &value);
    static napi_value AvroValueToNapi(napi_env env, avro_schema_t schema, avro_value_t &value);
    static napi_value FromBuffer_array(napi_env env, avro_schema_t schema, avro_value_t &value);
    static napi_value FromBuffer_union(napi_env env, avro_schema_t schema, avro_value_t &value);

    static bool ValidateString(napi_env env, napi_value value);
    static bool ValidateNumBer(napi_env env, napi_value value);
    static bool ValidateBoolean(napi_env env, napi_value value);
    static bool ValidateRecord(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateArray(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateMap(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateUnion(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateBytes(napi_env env, napi_value data);
    static bool ValidateFixed(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateEnum(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateDataAgainstSchema(napi_env env, napi_value data, avro_schema_t schema);
    static bool ValidateNull(napi_env env, napi_value data);
    static bool IsTheArrayType(napi_env env, napi_value data, napi_valuetype type);
    static napi_value IsValid(napi_env env, napi_callback_info info);

    static int Compare_Buffers(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2, avro_schema_t schema);
    static napi_value CompareBuffers(napi_env env, napi_callback_info info);
    
    static int long ReadLong(uint8_t* uData);
    static int MatchLong(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2);
    
    
    static float readFloatLE(const uint8_t* bytes);
    static float ReadFloat(uint8_t* buf, int len);
    static int MatchFloat(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2);
    
    static double readDoubleLE(const uint8_t* bytes);
    static double ReadDouble(uint8_t* buf, int len);
    static int MatchDouble(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2);

    // 消息头长度目前按照2计算，真是情况不固定，这里可能有问题
    static int MatchUnion(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2, avro_schema_t schema);
    static int MatchString(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2);

    static int MatchFixed(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2);

    // 未完成，不知道每个字段序列化后的数据长度，不好处理下个数据
    static int MatchRecord(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2, avro_schema_t schema);
    
    // 未完成，不知道每个字段序列化后的数据长度，不好处理下个数据
    static int MatchArray(const uint8_t* buffer_data, int buffer_len, const uint8_t* buffer_data2, int buffer_len2, avro_schema_t schema);

private:
    avro_schema_t schema_;
    std::string avroStr_;
};

void WriteAvroWorker(napi_env env, void *data);
void WriteAvroComplete(napi_env env, napi_status status, void *data);
napi_value SerializeToFile(napi_env env, napi_callback_info info);

void FreeAvroAsyncData(napi_env env, AvroAsyncData *data);
void ReadAvroWorker(napi_env env, void *data);
void ReadAvroComplete(napi_env env, napi_status status, void *data);
napi_value FromFile(napi_env env, napi_callback_info info);


#endif // avro_napi_H
